#pragma once
#include <iostream>
#include <typeinfo>
#include <assert.h>
/*
    如何实现一个Any类呢？
        如果仅仅简单的使用一个模板来定义，那么在调用的时候必须传入指定的类型Any<int> a =1，像这样指定类型接受数据就是Any类失去了意义
    解决办法：
        使用一个抽象类作为基类，让派生类使用模板继承，在派生类中存储真正的数据，因为这样可以使用父类指针指向子类来构造包含任意类型的
        子类对象，巧妙地绕过了需要传递指定类型的要求，从而得到一个可以存储任意类型的值的类
*/

class any
{
private:
    class holder{
    public:
        virtual ~holder(){}
        // =0声明为纯虚函数，包含纯虚函数的类不能直接创建对象，抽象类的作用是为派生类提供一个统一的接口规范
        virtual const std::type_info& type() = 0;
        virtual holder* clone()=0;
    };
    template<class T>
    class placeholder:public holder
    {
    public:
        //  真正存储的数据
        T _val;
    public:
        placeholder(const T& val):_val(val){}
        ~placeholder(){}
        // 返回数据类型
        const std::type_info& type(){return typeid(_val);}
        // clone出一个新的子类对象
        holder* clone(){return new placeholder<T>(_val);}

    };   
    holder* _content;
public:
    any():_content(nullptr){}
    template<class T>
    // Any(const T val):_content(new placeholder<T>(val)){}
    any(const T& val):_content(new placeholder<T>(val)){}

    any(const any& otherany):_content(otherany._content ? otherany._content->clone() : nullptr){}
    //返回子类对象保存数据的指针
    template<class T>
    T* get(){
        // 保证想要获取的类型和保存的数据类型一致
        assert(_content->type() == typeid(T));
        return &((placeholder<T>*)_content)->_val;
        
    }
    any& swap(any& any){
        std::swap(_content,any._content);
        return *this;
    }
    template<class T>
    any& operator=(const T& val){
        // 方法一：
        // _content = new placeholder<T>(val);
        // // 返回this的目的是为了能重复复制，类似于 a=b=c
        // 方法二：
        any(val).swap(*this);
        return *this;
    }
    any& operator=(const any& otherany){
        // 方法一：
        // _content=otherany._content?otherany._content->clone() : nullptr;     
        // 方法二：
        any(otherany).swap(*this);
        return *this;
    }
    ~any(){delete _content;}
};